package com.miyake.dsp.osa.method;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;

import com.miyake.dsp.ComplexArray;
import com.miyake.dsp.ScilabExecute;
import com.miyake.dsp.analyzer.PeakSearch;
import com.miyake.dsp.analyzer.PeakSearchSetting;
import com.miyake.dsp.common.CommonTool;
import com.miyake.dsp.common.UnitConverter;
import com.miyake.dsp.osa.AnalysisProperty;
import com.miyake.dsp.osa.lab.Fitting2;

public class Yokogawa implements NFCalc {

	private double ase;
	private double gain;

	private List<double[]> traces = new ArrayList<double[]>();
	private double[] subX;
	private Double fittingStart;
	private Double fittingEnd;
	private Double maskedStart;
	private Double maskedEnd;


	@Override
	public void setData(double[] x, double[] in, double[] out,
			AnalysisProperty setting, boolean fitInLog,
			int inPeakIndex, int outPeakIndex, int peakCenterIndex, double center) {
		traces.clear();

//		center = getAnritsuRound(center);
		this.fittingStart = setting.getFittingStart();
		this.fittingEnd = setting.getFittingEnd();
		this.maskedStart = center - setting.getMaskedSpan()/2.0;
		this.maskedEnd = center + setting.getMaskedSpan()/2.0;

//		fittingStart = getAnritsuRound(fittingStart);
//		fittingEnd = getAnritsuRound(fittingEnd);

		Extractor extractor = new Extractor(x);
		extractor.addData(in, "in");
		extractor.addData(out, "out");
		if (setting.isPoint()) {
			extractor.setPoint(this.fittingStart, this.fittingEnd);
		}
		else {
			extractor.setArea(this.fittingStart, this.fittingEnd, this.maskedStart, this.maskedEnd);
		}
//		subX = extractor.getBaseToBeFilled();

		double tmpAse = (out[extractor.getiEnd()] - out[extractor.getiStart()]) /
				(x[extractor.getiEnd()] - x[extractor.getiStart()]) * (x[inPeakIndex] - x[extractor.getiStart()]) + out[extractor.getiStart()];

		/* 暫定ASE算出 Ymzk */
		{
			double[] tmpx = extractor.getFittingDataX();
			double[] tmpy = extractor.getFittingData("out");
//			tmpAse = (tmpy[1] - tmpy[0]) / (tmpx[1] - tmpx[0]) * (x[inPeakIndex] - tmpx[0]) + tmpy[0];
			tmpAse = (tmpy[1] - tmpy[0]) / (tmpx[1] - tmpx[0]) * (x[peakCenterIndex] - tmpx[0]) + tmpy[0];
		}
		/////////////////

		/* 暫定GAIN算出 Ymzk */
		double tmpgain = (out[outPeakIndex] - tmpAse) / in[inPeakIndex];

		// �S�f�[�^��ASE�X�y�N�g�������
		Fitting2 fitting = new Fitting2(setting.getFormula());
		/* TraceB - (TraceA * 暫定GAIN)によるTraceC算出 Ymzk */
		double[] corr = ScilabExecute.execute("ret=data1 - data2*" + String.valueOf(tmpgain),
				new ComplexArray(out), new ComplexArray(in), "ret").getRealPart();
		corr = CommonTool.getFloor(corr, UnitConverter.toLinear(-135.0));
		extractor.addData(corr, "Corr");
		subX = extractor.getBaseToBeFilled();
		/* TraceCからFitting分データを切り出し Ymzk */
		double[] corr2 = extractor.getFittingData("Corr");
		if (corr2[corr2.length-1] < 0.0) {
			corr2[corr2.length-1] = 0.0;
		}

		/* というわけで切り出し部分のPeakIndexを算出 Ymzk */
//		int peakIndex2 = inPeakIndex - extractor.getiStart();
		int peakIndex2 = peakCenterIndex - extractor.getiStart();

		double[] originalX = extractor.getFittingDataX();
		NormalizeX nx2 = new NormalizeX(originalX, subX);
		if (fitInLog) {
			fitting.setOriginalData(nx2.getNomalizedOriginal(), UnitConverter.todBm(corr2));
		}
		else {
			fitting.setOriginalData(nx2.getNomalizedOriginal(), corr2);
		}

		double[] fit = fitting.getInterpolated(nx2.getNomalizedInterpolate());
		if (fitInLog) {
			fit = UnitConverter.toW(fit);
		}

		traces.add(ArrayUtils.subarray(corr, extractor.getiStart(), extractor.getiEnd()+1));
		traces.add(fit);

/*
		double[] in2 = ArrayUtils.subarray(in, extractor.getiStart(), extractor.getiEnd()+1);
		double[] newin = CommonTool.subtract(in2, fit);
		PeakSearch peakSearch = new PeakSearch(new PeakSearchSetting(10, 0.01));
		peakSearch.setSource(new ComplexArray(newin));
		double[] pi = peakSearch.getProcessed().getRealPart();
		if (pi.length > 0) {
			peakIndex2 = (int)pi[0];
		}
*/
		Double inPeak = in[inPeakIndex];
		Double outPeak = out[outPeakIndex];

//		ase = fitting.getAt(center - originalX[0]);// Center�
		ase = fit[peakIndex2];
		gain = (outPeak - ase) / inPeak;

	}

	private double getAnritsuRound(double center) {
		center = Math.round(center * 1000) / 1000.0;
		return center;
	}

	@Override
	public double getGain() {
		return gain;
	}

	@Override
	public double getAse() {
		return ase;
	}

	@Override
	public List<double[]> getTraces() {
		return traces;
	}

	@Override
	public double[] getSubX() {
		return subX;
	}

	@Override
	public Double getFittingStart() {
		return this.fittingStart;
	}

	@Override
	public Double getFittingEnd() {
		return this.fittingEnd;
	}

	@Override
	public Double getMaskedStart() {
		return this.maskedStart;
	}

	@Override
	public Double getMaskedEnd() {
		return this.maskedEnd;
	}

}
